using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Peak.Can.Basic
{
	public static class PCANBasic
	{
		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate TPCANStatus tPCAN_Initialize([MarshalAs(UnmanagedType.U1)] byte Channel, [MarshalAs(UnmanagedType.U2)] TPCANBaudrate Btr0Btr1, [MarshalAs(UnmanagedType.U1)] TPCANType HwType, uint IOPort, ushort Interrupt);

		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate TPCANStatus tPCAN_SetValue([MarshalAs(UnmanagedType.U1)] byte Channel, [MarshalAs(UnmanagedType.U1)] TPCANParameter Parameter, ref ulong OEM_Buffer, uint BufferLength);

		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate TPCANStatus tPCAN_FilterMessages([MarshalAs(UnmanagedType.U1)] byte Channel, uint FromID, uint ToID, [MarshalAs(UnmanagedType.U1)] TPCANMode Mode);

		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate TPCANStatus tPCAN_GetStatus([MarshalAs(UnmanagedType.U1)] byte Channel);

		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate TPCANStatus tPCAN_Uninitialize([MarshalAs(UnmanagedType.U1)] byte Channel);

		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate TPCANStatus tPCAN_Read([MarshalAs(UnmanagedType.U1)] byte Channel, out TPCANMsg MessageBuffer, out TPCANTimestamp TimestampBuffer);

		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate TPCANStatus tPCAN_ReadA([MarshalAs(UnmanagedType.U1)] byte Channel, out TPCANMsg MessageBuffer, IntPtr bufferPointer);

		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate TPCANStatus tPCAN_Write([MarshalAs(UnmanagedType.U1)] byte Channel, ref TPCANMsg MessageBuffer);

		[UnmanagedFunctionPointer(CallingConvention.StdCall)]
		private delegate TPCANStatus tPCAN_SetValueA([MarshalAs(UnmanagedType.U1)] byte Channel, [MarshalAs(UnmanagedType.U1)] TPCANParameter Parameter, ref uint NumericBuffer, uint BufferLength);

		public const byte PCAN_NONEBUS = 0;

		public const byte PCAN_ISABUS1 = 33;

		public const byte PCAN_ISABUS2 = 34;

		public const byte PCAN_ISABUS3 = 35;

		public const byte PCAN_ISABUS4 = 36;

		public const byte PCAN_ISABUS5 = 37;

		public const byte PCAN_ISABUS6 = 38;

		public const byte PCAN_ISABUS7 = 39;

		public const byte PCAN_ISABUS8 = 40;

		public const byte PCAN_DNGBUS1 = 49;

		public const byte PCAN_PCIBUS1 = 65;

		public const byte PCAN_PCIBUS2 = 66;

		public const byte PCAN_PCIBUS3 = 67;

		public const byte PCAN_PCIBUS4 = 68;

		public const byte PCAN_PCIBUS5 = 69;

		public const byte PCAN_PCIBUS6 = 70;

		public const byte PCAN_PCIBUS7 = 71;

		public const byte PCAN_PCIBUS8 = 72;

		public const byte PCAN_USBBUS1 = 81;

		public const byte PCAN_USBBUS2 = 82;

		public const byte PCAN_USBBUS3 = 83;

		public const byte PCAN_USBBUS4 = 84;

		public const byte PCAN_USBBUS5 = 85;

		public const byte PCAN_USBBUS6 = 86;

		public const byte PCAN_USBBUS7 = 87;

		public const byte PCAN_USBBUS8 = 88;

		public const byte PCAN_PCCBUS1 = 97;

		public const byte PCAN_PCCBUS2 = 98;

		public const int PCAN_PARAMETER_OFF = 0;

		public const int PCAN_PARAMETER_ON = 1;

		public const int PCAN_FILTER_CLOSE = 0;

		public const int PCAN_FILTER_OPEN = 1;

		public const int PCAN_FILTER_CUSTOM = 2;

		public const int PCAN_CHANNEL_UNAVAILABLE = 0;

		public const int PCAN_CHANNEL_AVAILABLE = 1;

		public const int PCAN_CHANNEL_OCCUPIED = 2;

		public const int LOG_FUNCTION_DEFAULT = 0;

		public const int LOG_FUNCTION_ENTRY = 1;

		public const int LOG_FUNCTION_PARAMETERS = 2;

		public const int LOG_FUNCTION_LEAVE = 4;

		public const int LOG_FUNCTION_WRITE = 8;

		public const int LOG_FUNCTION_READ = 16;

		private const int NO_ERROR = 0;

		private const int ERROR = -1;

		private static IntPtr hPCANDLL = IntPtr.Zero;

		private static IntPtr pPCAN_Initialize = IntPtr.Zero;

		private static IntPtr pPCAN_SetValue = IntPtr.Zero;

		private static IntPtr pPCAN_FilterMessages = IntPtr.Zero;

		private static IntPtr pPCAN_GetStatus = IntPtr.Zero;

		private static IntPtr pPCAN_Uninitialize = IntPtr.Zero;

		private static IntPtr pPCAN_Read = IntPtr.Zero;

		private static IntPtr pPCAN_ReadA = IntPtr.Zero;

		private static IntPtr pPCAN_Write = IntPtr.Zero;

		private static IntPtr pPCAN_SetValueA = IntPtr.Zero;

		public static int IntParseFast(string value)
		{
			int num = 0;
			for (int i = 0; i < value.Length; i++)
			{
				num = 10 * num + (value[i] - 48);
			}
			return num;
		}

		public static int TestDir(string value)
		{
			int result = 0;
			if (!Directory.Exists(value))
			{
				Console.WriteLine("Directory " + value + " not Exists");
				result = -1;
			}
			return result;
		}

		public static void LoadPCAN()
		{
			string dllToLoad = "PCANBasic.dll";
			string text = "PCANBasic.dll";
			if (!(hPCANDLL == IntPtr.Zero))
			{
				return;
			}
			string text2 = "CANData\\";
			string text3 = text2 + "CanDrv\\";
			string text4 = text2 + "OldCanDrv\\";
			string text5 = text3 + "x64\\";
			string text6 = text3 + "Win32\\";
			string text7 = text4 + "x64\\";
			string text8 = text4 + "Win32\\";
			string text9 = text6 + text;
			string text10 = text5 + text;
			string text11 = text8 + text;
			string text12 = text7 + text;
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string text13 = Environment.OSVersion.Version.ToString();
			string[] array = text13.Split('.');
			int num = IntParseFast(array[0]);
			text2 = directoryName + "\\CANData\\";
			text3 = text2 + "CanDrv\\";
			text4 = text2 + "OldCanDrv\\";
			text5 = text3 + "x64\\";
			text6 = text3 + "Win32\\";
			text7 = text4 + "x64\\";
			text8 = text4 + "Win32\\";
			text9 = text6 + text;
			text10 = text5 + text;
			text11 = text8 + text;
			text12 = text7 + text;
			int num2 = TestDir(text2);
			if (num2 == 0)
			{
				num2 |= TestDir(text3);
			}
			if (num2 == 0)
			{
				num2 |= TestDir(text4);
			}
			if (num2 == 0)
			{
				num2 |= TestDir(text5);
			}
			if (num2 == 0)
			{
				num2 |= TestDir(text6);
			}
			if (num2 == 0)
			{
				num2 |= TestDir(text7);
			}
			if (num2 == 0)
			{
				num2 |= TestDir(text8);
			}
			if (num2 == 0)
			{
				if (num > 5)
				{
					if (Environment.Is64BitOperatingSystem)
					{
						if (File.Exists(text10))
						{
							dllToLoad = text10;
						}
					}
					else if (File.Exists(text9))
					{
						dllToLoad = text9;
					}
				}
				else if (Environment.Is64BitOperatingSystem)
				{
					if (File.Exists(text12))
					{
						dllToLoad = text12;
					}
				}
				else if (File.Exists(text11))
				{
					dllToLoad = text11;
				}
			}
			else
			{
				MessageBox.Show("Load PCANBasic.dll from:\n" + directoryName + "NOT LOADED");
			}
			hPCANDLL = LoadLibrary(dllToLoad);
			if (hPCANDLL == IntPtr.Zero)
			{
				hPCANDLL = LoadLibrary("PCANBasic.dll");
				if (hPCANDLL == IntPtr.Zero)
				{
					MessageBox.Show("PCANBasic.dll: NOT LOADED");
				}
			}
			if (hPCANDLL != IntPtr.Zero)
			{
				pPCAN_Initialize = GetProcAddress(hPCANDLL, "CAN_Initialize");
				pPCAN_SetValue = GetProcAddress(hPCANDLL, "CAN_SetValue");
				pPCAN_FilterMessages = GetProcAddress(hPCANDLL, "CAN_FilterMessages");
				pPCAN_GetStatus = GetProcAddress(hPCANDLL, "CAN_GetStatus");
				pPCAN_Uninitialize = GetProcAddress(hPCANDLL, "CAN_Uninitialize");
				pPCAN_Read = GetProcAddress(hPCANDLL, "CAN_Read");
				pPCAN_ReadA = GetProcAddress(hPCANDLL, "CAN_Read");
				pPCAN_Write = GetProcAddress(hPCANDLL, "CAN_Write");
				pPCAN_SetValueA = GetProcAddress(hPCANDLL, "CAN_SetValue");
			}
		}

		[DllImport("kernel32.dll")]
		private static extern IntPtr LoadLibrary(string dllToLoad);

		[DllImport("kernel32.dll")]
		private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

		[DllImport("kernel32.dll")]
		private static extern bool FreeLibrary(IntPtr hModule);

		public static TPCANStatus Initialize(byte Channel, TPCANBaudrate Btr0Btr1)
		{
			return Initialize(Channel, Btr0Btr1, (TPCANType)0, 0u, 0);
		}

		private static TPCANStatus Initialize([MarshalAs(UnmanagedType.U1)] byte Channel, [MarshalAs(UnmanagedType.U2)] TPCANBaudrate Btr0Btr1, [MarshalAs(UnmanagedType.U1)] TPCANType HwType, uint IOPort, ushort Interrupt)
		{
			TPCANStatus result = TPCANStatus.PCAN_ERROR_UNKNOWN;
			if (hPCANDLL == IntPtr.Zero)
			{
				return result;
			}
			if (pPCAN_Initialize != IntPtr.Zero)
			{
				tPCAN_Initialize tPCAN_Initialize = (tPCAN_Initialize)Marshal.GetDelegateForFunctionPointer(pPCAN_Initialize, typeof(tPCAN_Initialize));
				result = tPCAN_Initialize(Channel, Btr0Btr1, HwType, IOPort, Interrupt);
			}
			else
			{
				MessageBox.Show("Failed to load function FT_CAN_Initialise.");
			}
			return result;
		}

		public static TPCANStatus SetValue([MarshalAs(UnmanagedType.U1)] byte Channel, [MarshalAs(UnmanagedType.U1)] TPCANParameter Parameter, ref ulong OEM_Buffer, uint BufferLength)
		{
			TPCANStatus result = TPCANStatus.PCAN_ERROR_UNKNOWN;
			if (hPCANDLL == IntPtr.Zero)
			{
				return result;
			}
			if (pPCAN_SetValue != IntPtr.Zero)
			{
				tPCAN_SetValue tPCAN_SetValue = (tPCAN_SetValue)Marshal.GetDelegateForFunctionPointer(pPCAN_SetValue, typeof(tPCAN_SetValue));
				result = tPCAN_SetValue(Channel, Parameter, ref OEM_Buffer, BufferLength);
			}
			else
			{
				MessageBox.Show("Failed to load function FT_CAN_SetValue.");
			}
			return result;
		}

		public static TPCANStatus FilterMessages([MarshalAs(UnmanagedType.U1)] byte Channel, uint FromID, uint ToID, [MarshalAs(UnmanagedType.U1)] TPCANMode Mode)
		{
			TPCANStatus result = TPCANStatus.PCAN_ERROR_UNKNOWN;
			if (hPCANDLL == IntPtr.Zero)
			{
				return result;
			}
			if (pPCAN_FilterMessages != IntPtr.Zero)
			{
				tPCAN_FilterMessages tPCAN_FilterMessages = (tPCAN_FilterMessages)Marshal.GetDelegateForFunctionPointer(pPCAN_FilterMessages, typeof(tPCAN_FilterMessages));
				result = tPCAN_FilterMessages(Channel, FromID, ToID, Mode);
			}
			else
			{
				MessageBox.Show("Failed to load function FT_CAN_FilterMessages.");
			}
			return result;
		}

		public static TPCANStatus GetStatus([MarshalAs(UnmanagedType.U1)] byte Channel)
		{
			TPCANStatus result = TPCANStatus.PCAN_ERROR_UNKNOWN;
			if (hPCANDLL == IntPtr.Zero)
			{
				return result;
			}
			if (pPCAN_GetStatus != IntPtr.Zero)
			{
				tPCAN_GetStatus tPCAN_GetStatus = (tPCAN_GetStatus)Marshal.GetDelegateForFunctionPointer(pPCAN_GetStatus, typeof(tPCAN_GetStatus));
				result = tPCAN_GetStatus(Channel);
			}
			else
			{
				MessageBox.Show("Failed to load function FT_CAN_GetStatus.");
			}
			return result;
		}

		public static TPCANStatus Uninitialize([MarshalAs(UnmanagedType.U1)] byte Channel)
		{
			TPCANStatus result = TPCANStatus.PCAN_ERROR_UNKNOWN;
			if (hPCANDLL == IntPtr.Zero)
			{
				return result;
			}
			if (pPCAN_Uninitialize != IntPtr.Zero)
			{
				tPCAN_Uninitialize tPCAN_Uninitialize = (tPCAN_Uninitialize)Marshal.GetDelegateForFunctionPointer(pPCAN_Uninitialize, typeof(tPCAN_Uninitialize));
				result = tPCAN_Uninitialize(Channel);
			}
			else
			{
				MessageBox.Show("Failed to load function FT_CAN_Uninitialize.");
			}
			return result;
		}

		public static TPCANStatus Read([MarshalAs(UnmanagedType.U1)] byte Channel, out TPCANMsg MessageBuffer, out TPCANTimestamp TimestampBuffer)
		{
			TPCANStatus result = TPCANStatus.PCAN_ERROR_UNKNOWN;
			MessageBuffer = default(TPCANMsg);
			TimestampBuffer = default(TPCANTimestamp);
			if (hPCANDLL == IntPtr.Zero)
			{
				return result;
			}
			if (pPCAN_Read != IntPtr.Zero)
			{
				tPCAN_Read tPCAN_Read = (tPCAN_Read)Marshal.GetDelegateForFunctionPointer(pPCAN_Read, typeof(tPCAN_Read));
				result = tPCAN_Read(Channel, out MessageBuffer, out TimestampBuffer);
			}
			else
			{
				MessageBox.Show("Failed to load function FT_CAN_Read.");
			}
			return result;
		}

		public static TPCANStatus Read([MarshalAs(UnmanagedType.U1)] byte Channel, out TPCANMsg MessageBuffer, IntPtr bufferPointer)
		{
			TPCANStatus result = TPCANStatus.PCAN_ERROR_UNKNOWN;
			MessageBuffer = default(TPCANMsg);
			if (hPCANDLL == IntPtr.Zero)
			{
				return result;
			}
			if (pPCAN_ReadA != IntPtr.Zero)
			{
				tPCAN_ReadA tPCAN_ReadA = (tPCAN_ReadA)Marshal.GetDelegateForFunctionPointer(pPCAN_ReadA, typeof(tPCAN_ReadA));
				result = tPCAN_ReadA(Channel, out MessageBuffer, bufferPointer);
			}
			else
			{
				MessageBox.Show("Failed to load function FT_CAN_Read.");
			}
			return result;
		}

		public static TPCANStatus Write([MarshalAs(UnmanagedType.U1)] byte Channel, ref TPCANMsg MessageBuffer)
		{
			TPCANStatus result = TPCANStatus.PCAN_ERROR_UNKNOWN;
			if (hPCANDLL == IntPtr.Zero)
			{
				return result;
			}
			if (pPCAN_Write != IntPtr.Zero)
			{
				tPCAN_Write tPCAN_Write = (tPCAN_Write)Marshal.GetDelegateForFunctionPointer(pPCAN_Write, typeof(tPCAN_Write));
				result = tPCAN_Write(Channel, ref MessageBuffer);
			}
			else
			{
				MessageBox.Show("Failed to load function FT_CAN_Write.");
			}
			return result;
		}

		public static TPCANStatus SetValue([MarshalAs(UnmanagedType.U1)] byte Channel, [MarshalAs(UnmanagedType.U1)] TPCANParameter Parameter, ref uint NumericBuffer, uint BufferLength)
		{
			TPCANStatus result = TPCANStatus.PCAN_ERROR_UNKNOWN;
			if (hPCANDLL == IntPtr.Zero)
			{
				return result;
			}
			if (pPCAN_SetValueA != IntPtr.Zero)
			{
				tPCAN_SetValueA tPCAN_SetValueA = (tPCAN_SetValueA)Marshal.GetDelegateForFunctionPointer(pPCAN_SetValueA, typeof(tPCAN_SetValueA));
				result = tPCAN_SetValueA(Channel, Parameter, ref NumericBuffer, BufferLength);
			}
			else
			{
				MessageBox.Show("Failed to load function FT_CAN_SetValue.");
			}
			return result;
		}
	}
}
